#include "x_logger.h"
#include "x_logfile.h"
#include <mutex>
#include <cassert>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/time.h>

namespace x_log
{

//局部线程存储
__thread char t_errnobuf[256];
__thread char t_time[64];
__thread time_t t_lastSecond;

const char* strerror_ts(int syserrno)
{
    return strerror_r(syserrno, t_errnobuf, sizeof(t_errnobuf));
}

//使用系统调用获取线程ID
pid_t gettid()
{
  return static_cast<pid_t>(::syscall(SYS_gettid));
}
namespace curentThread
{
    __thread int t_cachedTid = 0;
    __thread char t_tidString[32]; //字符串格式的线程ID
    __thread int  t_tidStrLen; //字符串化的线程的ID长度

    //缓存线程ID
    void cacheTid()
    {
        if (0 == t_cachedTid)
        {
            t_cachedTid = x_log::gettid();
            t_tidStrLen = snprintf(t_tidString, sizeof(t_tidString), "[%5d] ", t_cachedTid);
        }
    }
} //end namespace curentThread

Timestamp Timestamp::now()
{
    struct timeval tv{};
    gettimeofday(&tv, nullptr);
    int64_t seconds = tv.tv_sec;
    //将秒数换算为微妙
    return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);
}

//初始化默认日志界别为INFO
CLogger::LogLevel g_logLevel = CLogger::X_INFO;

const char* LogLevelName[CLogger::NUM_LOG_LEVELS] = 
{
    "TRACE ",
    "DEBUG ",
    "INFO  ",
    "WARN  ",
    "ERROR ",
    "FATAL ",
};


class T
{
public:
    T(const char* str, unsigned len)
     : m_str(str), m_len(len)
     {
        assert(strlen(str) == m_len);
     }
    const char* m_str;
    const unsigned m_len;
};

inline CLogStream& operator<< (CLogStream& s, T v)
{
    s.append(v.m_str, v.m_len);
    return s;
}

std::mutex LogFileLocker;
std::unique_ptr<CLogFile> g_file_out;

void defaultOutPut(const char* msg, int len)
{
    std::lock_guard<std::mutex> locker(LogFileLocker);
    g_file_out = std::make_unique<CLogFile>(CLogger::LogFileName, false);
    g_file_out->writeLog(msg, len);
}
void defaultFlush()
{
    std::lock_guard<std::mutex> locker(LogFileLocker);
    if (g_file_out)
    {
        g_file_out = std::make_unique<CLogFile>(CLogger::LogFileName, false);
    }
    g_file_out->flushLog();
}
void standOutput(const char* msg, int len)
{
    size_t n = fwrite(msg, 1, len, stdout);
    (void)n;
}
void standFlush()
{
    fflush(stdout);
}

//默认到标准输出
CLogger::LogOutPutFunc CLogger::LogOut = standOutput;
CLogger::LogFlushFunc CLogger::LogFlush = standFlush;
std::mutex CLogger::OutMutex_;
std::mutex CLogger::FlushMutex_;
std::string CLogger::LogFileName;


CLogger::Impl::Impl(LogLevel level, const BaseFile& filename, int line)
  : m_time(Timestamp::now()),
    m_stream(),
    m_level(level),
    m_filename(filename.data_),
    m_line(line)
{
    formatTime();
#if 1
    //支持线程ID的输出
    curentThread::getThreadID();
    m_stream << T(curentThread::tidtoString(), curentThread::tidStrLength());
#endif
    m_stream << T(LogLevelName[level], 6);
}

void CLogger::Impl::formatTime()
{
    int64_t microSecondsSinceEpoch = m_time.getMicroSecondsSinceEpoch();
    auto seconds = static_cast<time_t>(microSecondsSinceEpoch / Timestamp::kMicroSecondsPerSecond);
    if (seconds != t_lastSecond)
    {
        t_lastSecond = seconds;
        struct tm tm_time{};
        ::localtime_r(&seconds, &tm_time);
        ::snprintf(t_time, sizeof(t_time), "%4d-%02d-%02d %02d:%02d:%02d ",
        tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
        tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
    }
#if 0
    //微妙级别的时间
    char usbuffer[9] = {0};
    snprintf(usbuffer, sizeof(usbuffer), ".%06d ", microseconds);
    m_stream << T(t_time, 17) << T(usbuffer, 8);
#else
    m_stream << T(t_time, 20);
#endif
}

void CLogger::Impl::ends()
{
    //m_stream << " - " << m_filename << ':' << m_line << '\n';
    m_stream << '\n';
}

CLogger::CLogger(BaseFile filename, int line)
    : m_impl(X_INFO, filename, line)
{
    m_impl.m_stream << m_impl.m_filename << ':' << m_impl.m_line << " - ";
}

CLogger::CLogger(BaseFile filename, int line, LogLevel level)
    : m_impl(level, filename, line)
{
    m_impl.m_stream << m_impl.m_filename << ':' << m_impl.m_line << " - ";
}

CLogger::CLogger(BaseFile filename, int line, const int syserrno)
    : m_impl(X_ERROR, filename, line)
{
    if (0 != syserrno)
    {
        m_impl.m_stream << m_impl.m_filename << ':' << m_impl.m_line << " - " << strerror_ts(syserrno) << " (errno=" << syserrno << ") :";
    }
}



CLogger::CLogger(BaseFile filename, int line, LogLevel level, const char * funcname)
    : m_impl(level, filename, line)
{
    m_impl.m_stream << funcname << ',' << m_impl.m_filename << ':' << m_impl.m_line << " - ";
}

CLogger::~CLogger()
{
    m_impl.ends();
    const CLogStream::Buffer& logbuf(stream().buffer());
    LogOut(logbuf.data(), logbuf.length());
    LogFlush();
}

void CLogger::setLogLevel(CLogger::LogLevel level)
{
    g_logLevel = level;
}

void CLogger::setLogOutPut(LogOutPutFunc out)
{
    std::lock_guard<std::mutex> locker(OutMutex_);
    LogOut = out;
}

void CLogger::setFlush(LogFlushFunc flush)
{
    std::lock_guard<std::mutex> locker(FlushMutex_);
    LogFlush = flush;
}

void CLogger::setLogFileName(std::string file_name)
{
    LogFileName = std::move(file_name);
}

} //namespace x_log



